import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.ArrayList;

import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;

public class Courier{
	

	private static ArrayList<String> history = new ArrayList<String>();
	private static int historyIndex = -1;
	
	public static void main(String[] args){
		final JFrame frame = new JFrame("Courier");
		frame.setBounds(new Rectangle(0,0,1400,775));
		frame.setLayout(new BorderLayout());
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	
		final JSplitPane splitPane = new JSplitPane();
		splitPane.setBounds(0, 0, 1400, 720);
		splitPane.setDividerLocation(0.5);
		
		JPanel statusBar = new JPanel();
		statusBar.setLayout(new BorderLayout());
		JLabel statusLabel = new JLabel("Status: ");
		final JLabel status = new JLabel();
		statusBar.add(statusLabel, BorderLayout.WEST);
		statusBar.add(status, BorderLayout.CENTER);
		
		frame.add(splitPane, BorderLayout.CENTER);
		frame.add(statusBar, BorderLayout.SOUTH);
		
		JTabbedPane leftSide = new JTabbedPane();
		leftSide.setBounds(0,0, frame.getWidth() / 2, frame.getHeight());
		
		JPanel browser = new JPanel();
		browser.setBounds(leftSide.getBounds());
		browser.setLayout(new BorderLayout());
		
		JPanel navigationBar = new JPanel();
		JPanel addressPane = new JPanel();
		JPanel navigationButtons = new JPanel();
		
		addressPane.setLayout(new BorderLayout());
		navigationBar.setLayout(new BorderLayout());
		navigationButtons.setLayout(new BorderLayout());
		
		JButton navigateButton = new JButton("Go!");
		final JTextField addressBar = new JTextField("http://www.cc.gatech.edu/classes/AY2012/cs4470_fall/");
		navigationBar.setBounds(new Rectangle(0,0,600,50));
		//navigationBar.setPreferredSize(new Dimension(600, 50));
		
		addressPane.add(new JLabel("URL:"), BorderLayout.WEST);
		addressPane.add(addressBar, BorderLayout.CENTER);
		addressPane.add(navigateButton, BorderLayout.EAST);
		final JButton backButton = new JButton("\t<\t");
		final JButton forwardButton = new JButton("\t>\t");
		final JButton refreshButton = new JButton("Refresh");
		backButton.setEnabled(false);
		forwardButton.setEnabled(false);
		
		navigationButtons.add(backButton, BorderLayout.LINE_START);
		navigationButtons.add(forwardButton, BorderLayout.CENTER);
		navigationButtons.add(refreshButton, BorderLayout.LINE_END);
		
		navigationBar.add(addressPane, BorderLayout.NORTH);
		navigationBar.add(navigationButtons, BorderLayout.LINE_START);
		browser.add(navigationBar, BorderLayout.NORTH);
		
		JScrollPane htmlScroller = new JScrollPane();
		//htmlScroller.setPreferredSize(new Dimension(500, 600));
		final JEditorPane htmlDisplay = new JEditorPane();
		//htmlDisplay.setPreferredSize(new Dimension(500, 600));
		htmlDisplay.setEditable(false);
		htmlDisplay.setText("Home page");
		htmlScroller.setViewportView(htmlDisplay);
		browser.add(htmlScroller, BorderLayout.CENTER);
		leftSide.add("Browser", browser);
		
		JPanel addressBook = new JPanel();
		Object[] columns = {"Last", "First", "Home", "Cell", "E-mail", "Street", "City", "State", "ZIP", "Comments"};
		Object[][] data = {
				{"Clements", "Patrick", "(803) 867-5309", "(404) 555-5555", "pclements6@gatech.edu", "2813 Fontainebleau Dr", "Atlanta", "GA", "30360", "Cool guy!"},
				{"Blow", "Joe", "", "(404) 911-9999", "joeB@domain.com", "123 Peachtree St. NW", "Atlanta", "GA", "30060", "classmate"}
		};
		final JEditorPane contactDisplay = new JEditorPane();
		contactDisplay.setEditable(false);
		contactDisplay.setPreferredSize(new Dimension(splitPane.getWidth()/2, splitPane.getHeight()/2));
		final JTable addressTable = new JTable(data, columns);
		addressTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		JScrollPane tableScroller = new JScrollPane();
		tableScroller.setPreferredSize(new Dimension(splitPane.getWidth()/2, 200));
		tableScroller.setViewportView(addressTable);
		addressBook.setLayout(new BorderLayout());
		addressBook.add(tableScroller, BorderLayout.NORTH);
		addressBook.add(contactDisplay, BorderLayout.CENTER);
		leftSide.add("Address Book", addressBook);
		
		JPanel rightSide = new JPanel();
		SpringLayout rightSideLayout = new SpringLayout();
		rightSide.setLayout(rightSideLayout);
		JScrollPane canvasScroller = new JScrollPane();
		CourierCanvas canvas = new CourierCanvas();
		CourierButtonPanel buttons = new CourierButtonPanel(canvas);
		canvas.buttonPanel = buttons;
		canvasScroller.setPreferredSize(new Dimension(675,750));
		canvasScroller.setMaximumSize(new Dimension(675, 750));
		buttons.setPreferredSize(new Dimension(675, 100));
		canvasScroller.setViewportView(canvas);
		rightSide.add(canvasScroller);
		rightSide.add(buttons);
		rightSideLayout.putConstraint(SpringLayout.WEST, rightSide, 5, SpringLayout.WEST, canvasScroller);
		rightSideLayout.putConstraint(SpringLayout.EAST, rightSide, 5, SpringLayout.EAST, canvasScroller);
		rightSideLayout.putConstraint(SpringLayout.NORTH, rightSide, 5, SpringLayout.NORTH, canvasScroller);
		rightSideLayout.putConstraint(SpringLayout.NORTH, buttons, 5, SpringLayout.SOUTH, canvasScroller);
		rightSideLayout.putConstraint(SpringLayout.WEST, rightSide, 5, SpringLayout.WEST, buttons);
		rightSideLayout.putConstraint(SpringLayout.EAST, rightSide, 5, SpringLayout.EAST, buttons);
		rightSideLayout.putConstraint(SpringLayout.SOUTH, rightSide, 5, SpringLayout.SOUTH, buttons);	
		

		splitPane.setLeftComponent(leftSide);
		splitPane.setRightComponent(rightSide);
		
		frame.addComponentListener( new ComponentListener(){

			@Override
			public void componentHidden(ComponentEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void componentMoved(ComponentEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void componentResized(ComponentEvent e) {
				if(e.getComponent()==frame){
					calculateResize(frame, splitPane);
				}
				
			}

			@Override
			public void componentShown(ComponentEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			}
		);
		
		//listen for addressBook selection changes
		addressTable.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
			
				public void valueChanged(ListSelectionEvent e){
					 if (e.getValueIsAdjusting())
				          return;
					 int row = addressTable.getSelectedRow();
					 String display = "";
					 for(int i = 0; i<addressTable.getColumnCount(); i++){
						 display += addressTable.getColumnName(i)+":\t";
						 display += addressTable.getValueAt(row, i);
						 display += "\n";
					 }
					 contactDisplay.setText(display);
				}
			}
		);
		
		//listen for link clicks in the editor pane
		htmlDisplay.addHyperlinkListener(new HyperlinkListener() {

		    public void hyperlinkUpdate(HyperlinkEvent e) {
		        if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
		            JEditorPane pane = (JEditorPane) e.getSource();
		            if (e instanceof HTMLFrameHyperlinkEvent) {
		                HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
		                HTMLDocument doc = (HTMLDocument) pane.getDocument();
		                doc.processHTMLFrameHyperlinkEvent(evt);
		            } else {
		                try {
		                    addressBar.setText(e.getURL().toString());
		                    navigate(addressBar, htmlDisplay, true);
			                status.setText(addressBar.getText());		                    
		                } catch (Throwable t) {
		                    t.printStackTrace();
		                }
		            }
		        }
		    }
		});

		//navigate on button click
         navigateButton.addActionListener(
		        new ActionListener() {

		            public void actionPerformed(ActionEvent e) {
		                navigate(addressBar, htmlDisplay, true);
		                status.setText(addressBar.getText());
		                backButton.setEnabled(true);
		            }
		        });
         
         backButton.addActionListener(
 		        new ActionListener() {

 		            public void actionPerformed(ActionEvent e) {
 		            	forwardButton.setEnabled(true);
 		            	System.out.println("Back Button, current url: "+history.get(historyIndex));
 		            	addressBar.setText(history.get(--historyIndex));
 		            	if(historyIndex <=0)
 		            		backButton.setEnabled(false);
 		            	System.out.println("Back Button, new url: "+history.get(historyIndex));
 		                navigate(addressBar, htmlDisplay, false);
 		                status.setText(addressBar.getText());
 		            }
 		        });	
         
         forwardButton.addActionListener(
 		        new ActionListener() {

 		            public void actionPerformed(ActionEvent e) {
 		            	backButton.setEnabled(true);
 		            	if(historyIndex < history.size())
 		            		addressBar.setText(history.get(++historyIndex));
 		            	System.out.println("forward, historyIndex "+historyIndex+" historySize: "+history.size());
 		            	if(historyIndex >= history.size() - 1)
 		            		forwardButton.setEnabled(false);
 		                navigate(addressBar, htmlDisplay, false);
 		                status.setText(addressBar.getText());
 		            }
 		        });	
         
         refreshButton.addActionListener(
 		        new ActionListener() {

 		            public void actionPerformed(ActionEvent e) {
 		            	htmlDisplay.setText("Loading...");
 		                navigate(addressBar, htmlDisplay, false);
 		                status.setText(addressBar.getText());
 		            }
 		        });	
         
         //navigate to page upon enter in address bar
         addressBar.addKeyListener(new KeyAdapter() {
             public void keyReleased(KeyEvent e) {
                 if(e.getKeyCode() == KeyEvent.VK_ENTER){
                	backButton.setEnabled(true);
                	navigate(addressBar, htmlDisplay, true);
                	forwardButton.setEnabled(false);
	                status.setText(addressBar.getText());
                 }
               }

               public void keyTyped(KeyEvent e) {
               }

               public void keyPressed(KeyEvent e) {
               }
         });
         navigate(addressBar, htmlDisplay, true);
         status.setText(addressBar.getText());
         frame.setVisible(true);
	}
	
	public static void calculateResize(JFrame frame, JSplitPane splitPane){
		splitPane.setDividerLocation(splitPane.getWidth() / 2);
		for(Component child : splitPane.getComponents()){
			//child.setBounds(0, 0, splitPane.getWidth()/2, splitPane.getHeight());
		}
	}
	
	public static void navigate(JTextField addressBar, JEditorPane htmlDisplay, boolean updateHistory) {
		try {
        	if(!addressBar.getText().contains("http")){
        		addressBar.setText("http://"+addressBar.getText().trim());
        	}
        	htmlDisplay.setPage(addressBar.getText().trim());
        	if(updateHistory){
        		for(int i = 0; i<history.size(); i++){
        			if(i > historyIndex)
        				history.remove(i);
        		}
	        	history.add(addressBar.getText().trim());
	        	historyIndex++;
        	}
        	printHistoryList();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
	}
	
	public static void printHistoryList() {
		String hist = "history: \n";
		for(String url : history){
			hist+=url+"\n";
		}
		System.out.println(hist);
	}
}